/*
** Copyright (C) 2010 Calin Radoni
**
** This file is part of CHScanner.
**
** CHScanner is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** CHScanner is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with CHScanner. If not, see <http://www.gnu.org/licenses/>.
*/

#pragma once

#include "PacketDefinitions.h"

class PacketBuilder
{
private:
	BYTE* packet;
	int packSize;

	/// Computes the IP checksum
	USHORT ComputeIpCheckSum(USHORT* buh, int len);

	/// Computes checksum
	USHORT ComputeCheckSum(USHORT *buffer, int size, USHORT* prefix);

	/*
	/// Builds a custom IP Header
		\param[out] Dest     Destination - The result is written here
		\param[in]  dwSA     Source IP Address
		\param[in]  dwDA     Destination IP Address
		\param[in]  bTOS     Type of service
		\param[in]  wLEN     Length
		\param[in]  wID      IP Identifier
		\param[in]  wFragOff Fragment offset and Flags
		\param[in]  bTTL     Time to live
		\param[in]  bProto   Protocol
	*/
	bool BuildIPHeader(BYTE* Dest, DWORD dwSA, DWORD dwDA, BYTE bTOS, WORD wLen, WORD wID, WORD wFragOff, BYTE bTTL, BYTE bProto);
	bool BuildIPHeaderWithOptions(
			BYTE* Dest, DWORD dwSA, DWORD dwDA, BYTE bTOS, WORD wLen, WORD wID, WORD wFragOff, BYTE bTTL, BYTE bProto,
			BYTE* bpIpOpt,			///< IP options
			WORD  wIpOptLen			///< length of IP options
		);

protected:
	BYTE ethFF[6];
	BYTE eth00[6];

public:
	PacketBuilder(void);
	~PacketBuilder(void);

/* ---------------------- */
	bool BuildPacketTCP(
			DWORD dwSA, DWORD dwDA,		///< source and destination address
			WORD wSP, WORD wDP,			///< source and destination port

			BYTE bTOS,					///< type of service
			WORD wID,					///< ip id
			WORD wFragOff,				///< fragment offset + fragment flags
			BYTE bTTL,					///< time to live

			DWORD dwSeq,				///< sequence
			DWORD dwAck,				///< acknowledge
			BYTE bFlags,				///< tcp flags
			WORD wWindow,				///< window
			WORD wUrgent,				///< urgent pointer

			BYTE* bpOpt,				///< options
			DWORD dwOptLen,				///< length of options

			BYTE* bpData,				///< data
			DWORD dwDataLen				///< length of data
		);

/* ---------------------- */
	bool BuildPacketICMP(
			DWORD dwSA, DWORD dwDA,		///< source and destination address

			BYTE bTOS,					///< type of service
			WORD wID,					///< ip id
			WORD wFragOff,				///< fragment offset + fragment flags
			BYTE bTTL,					///< time to live

			BYTE bType,
			BYTE bCode,
			WORD wIDicmp,
			WORD wSeq,

			BYTE* bpData,				///< data
			DWORD dwDataLen				///< length of data
		);

/* ---------------------- */
	bool BuildPacketEmptyIpProto(
			DWORD dwSA, DWORD dwDA,		///< source and destination address

			BYTE bTOS,					///< type of service
			WORD wID,					///< ip id
			WORD wFragOff,				///< fragment offset + fragment flags
			BYTE bTTL,					///< time to live

			BYTE bProtocol				///< protocol
		);

/* ---------------------- */
	bool BuildPacketUDP(
			DWORD dwSA, DWORD dwDA,		///< source and destination address

			BYTE bTOS,					///< type of service
			WORD wID,					///< ip id
			WORD wFragOff,				///< fragment offset + fragment flags
			BYTE bTTL,					///< time to live

			WORD wSP, WORD wDP,			///< source and destination port

			BYTE* bpData,				///< data
			DWORD dwDataLen				///< length of data
		);

/* ---------------------- */
    bool BuildPacketARP(
			WORD arpCode,
			BYTE srcMacEthIn[6],
			BYTE srcMacIn[6],
			BYTE srcIpIn[4],
			BYTE dstMacEthIn[6],
			BYTE dstMacIn[6],
			BYTE dstIpIn[4]
		);

    bool BuildPacketARPDotQ(
			WORD arpCode,
			BYTE srcMacEthIn[6],
			BYTE srcMacIn[6],
			BYTE srcIpIn[4],
			BYTE dstMacEthIn[6],
			BYTE dstMacIn[6],
			BYTE dstIpIn[4],
			BYTE priorityIn,
			WORD vlanIdIn
		);

/* ---------------------- */
	bool BuildPacketIGMPQuery(
			DWORD dwSA, DWORD dwDA,		///< source and destination address

			BYTE bTOS,					///< type of service
			WORD wID,					///< ip id
			WORD wFragOff,				///< fragment offset + fragment flags
			BYTE bTTL,					///< time to live

			BYTE version,				///< 1, 2 or 3
			BYTE maxResponseTime,		///< as in RFC 3376. IGNORED if version==1 (eq.0) !
			BYTE groupAddress[4]		///< ignored for version 1 (= 0.0.0.0)
		);

/* ---------------------- */
	bool BuildPacketGvrpSingle(
			BYTE eventIn,				///< from 0 (Leave All) to 5 (Empty)
			WORD vidIn					///< ignored in case of LeaveAll event
		);

/* ---------------------- */
	bool AddEthernetHeader(BYTE srcMACIn[6], BYTE dstMACIn[6], WORD lenTypeIn);

/* ---------------------- */
	bool AddEthernetHeaderGVRP(BYTE srcMACIn[6]);
	bool AddEthernetHeaderGMRP(BYTE srcMACIn[6]);
	bool AddEthernetHeaderSTP(BYTE srcMACIn[6]);

/* ---------------------- */
	bool AddEthernetHeaderDotQ(BYTE srcMACIn[6], BYTE dstMACIn[6], WORD lenTypeIn, BYTE priorityIn, WORD vlanIdIn);
	bool AddEthernetHeaderDotQDotQ(BYTE srcMACIn[6], BYTE dstMACIn[6], WORD lenTypeIn, BYTE priorityIn1, WORD vlanIdIn1, BYTE priorityIn2, WORD vlanIdIn2);

/* ---------------------- */
	bool AddEthernetHeaderForIPMulticast(BYTE srcMACIn[6], DWORD dwDA, WORD lenTypeIn);	// RFC 1112
	bool IsIPv4MulticastAddress(DWORD addrIn);

/* ---------------------- */
	BYTE* GetPacket(void);
	DWORD GetPacketSize(void);

/* ---------------------- */
/*
	bool SendPacket(DWORD DestAddr, WORD DestPort);
		// DestAddr is obtained from inet_addr(char*) !
		// DestPort is the port ! Network order is made by this function.
*/
};
